<?php

class Code
{
    private array $info;
    private array $storeHouse;
    private array $config;

    /**
     * AREA 一级区域枚举项配置
     */
    const AREA_ENUM_US_WEST = 'US_WEST';
    const AREA_ENUM_US_SOUTH = 'US_SOUTH';
    const AREA_ENUM_US_EAST = 'US_EAST';

    /**
     * 二级区域枚举项配置
     */
    const AREA_NEXT_ENUM_NORMAL = 'normal';
    const AREA_NEXT_ENUM_GA = 'GA';

    /**
     * 三级区域枚举项配置
     */
    const AREA_LAST_ENUM_OVERSIZE = 'oversize';
    const AREA_LAST_ENUM_WEIGHT = 'weight';
    const AREA_LAST_ENUM_AHS_WEIGHT = 'ahs_weight';
    const AREA_LAST_ENUM_WEIGHT_RANGE = 'weight_range';
    const AREA_LAST_ENUM_AHS = 'ahs';
    const AREA_LAST_ENUM_UPS = 'ups';
    const AREA_LAST_ENUM_NORMAL = 'normal';

    public string $areaFirstEnumKey = "";
    public string $areaNextEnumKey = "";
    public string $areaLastEnumKey = "";


    /**
     * @param array $storehouse
     * @param array $info
     * @param array $config
     */
    private function __construct(array $storehouse, array $info, array $config)
    {
        $this->storeHouse = $storehouse;
        $this->info = $info;
        $this->config = $config;
    }

    /**
     * @var array
     */
    private static array $instance = [];

    /**
     * 获取实例化对象
     *
     * @param array $storehouse
     * @param array $info
     * @param array $config
     * @return self
     */
    public static function getInstance(array $storehouse, array $info, array $config): Code
    {
        $key = md5(vsprintf("%s_%s_%s", [
            json_encode($storehouse),
            json_encode($info),
            json_encode($config)
        ]));

        if (empty($instance[$key]) || !($instance[$key] instanceof self)) {
            $instance[$key] = new self($storehouse, $info, $config);
        }

        return $instance[$key];
    }

    /**
     * 通过实例化对象参数获取三级数据对应的key
     *
     * @return $this
     */
    public function setAreaLevelEnumKey(): Code
    {
        $weight = $this->info['weight'] ?? null;
        $type = $this->info['type'] ?? null;
        $usArea = $this->storeHouse["us_area"] ?? null;

        // 获取一级&二级key
        switch ($usArea) {
            case self::AREA_ENUM_US_WEST:
                $this->areaFirstEnumKey = self::AREA_ENUM_US_WEST;
                $this->areaNextEnumKey = self::AREA_NEXT_ENUM_NORMAL;
                break;
            case self::AREA_ENUM_US_SOUTH:
                $this->areaFirstEnumKey = self::AREA_ENUM_US_SOUTH;
                $this->areaNextEnumKey = ($this->storeHouse["name"] == "KC-GA2" ? self::AREA_NEXT_ENUM_GA : self::AREA_NEXT_ENUM_NORMAL);
                break;
            default:
                $this->areaFirstEnumKey = self::AREA_ENUM_US_EAST;
                $this->areaNextEnumKey = self::AREA_NEXT_ENUM_NORMAL;
                break;
        }

        // 获取三级key
        if ($this->areaFirstEnumKey == self::AREA_ENUM_US_SOUTH && $this->storeHouse['name'] != 'KC-GA2') {
            //1.实重在0-70lbs且无oversize
            if ($weight <= 70 && !in_array($type, [3])) {  // oversize
                $this->areaLastEnumKey = "oversize";
                //1.0-70lbs且有oversize 2.70lbs以上全部
            } else {
                $this->areaLastEnumKey = "normal";
            }
        } else {
            if (in_array($type, [3, 4])) {
                // oversize or out-space
                $this->areaLastEnumKey = "oversize";
            } elseif ($weight > 70) {
                $this->areaLastEnumKey = "ahs_weight";
            } elseif ($weight >= 47 && $weight <= 70) {
                // AHS Weight
                $this->areaLastEnumKey = "weight_range";
            } elseif ($type == 1) {
                // AHS DIM
                $this->areaLastEnumKey = "ahs";
            } elseif ($weight >= 16 && $weight <= 46) {
                // normal
                $this->areaLastEnumKey = "normal";
            } else {
                // UPS
                $this->areaLastEnumKey = "ups";
            }
        }

        echo vsprintf("一级key: %s |  二级key: %s |  三级key: %s" . PHP_EOL, [
            $this->areaFirstEnumKey, $this->areaNextEnumKey, $this->areaLastEnumKey
        ]);

        return $this;
    }


    /**
     * 获取状态码默认值数组数据
     *
     * @return string[][][]
     */
    public function getDefaultCode(): array
    {
        return [
            self::AREA_ENUM_US_WEST => [
                self::AREA_NEXT_ENUM_NORMAL => [
                    self::AREA_LAST_ENUM_OVERSIZE => "FEDEXOVERSIZE",
                    self::AREA_LAST_ENUM_AHS_WEIGHT => "FEDEX-OS-GROUND",
                    self::AREA_LAST_ENUM_WEIGHT_RANGE => "FEDEX-WEIGHT-HOME",
                    self::AREA_LAST_ENUM_AHS => "FEDEX-WEIGHT-HOME",
                    self::AREA_LAST_ENUM_NORMAL => "FEDEX-HOMEDELIVERY",
                    self::AREA_LAST_ENUM_UPS => "UPSGROUND",
                ]
            ],
            self::AREA_ENUM_US_SOUTH => [
                self::AREA_NEXT_ENUM_GA => [
                    self::AREA_LAST_ENUM_OVERSIZE => "FEDEXOVERSIZE",
                    self::AREA_LAST_ENUM_AHS_WEIGHT => "GASA-FEDEX-GROUND",
                    self::AREA_LAST_ENUM_WEIGHT_RANGE => "GASA-FEDEX-HD",
                    self::AREA_LAST_ENUM_AHS => "GASA-FEDEX-HD",
                    self::AREA_LAST_ENUM_NORMAL => "FEDEX-HOMEDELIVERY",
                    self::AREA_LAST_ENUM_UPS => "UPSGROUND",
                ],
                self::AREA_NEXT_ENUM_NORMAL => [
                    self::AREA_LAST_ENUM_OVERSIZE => "GANW-FEDEX-HD",
                    self::AREA_LAST_ENUM_NORMAL => "GANW-FEDEX-GROUND",
                ]
            ],
            self::AREA_ENUM_US_EAST => [
                self::AREA_NEXT_ENUM_NORMAL => [
                    self::AREA_LAST_ENUM_OVERSIZE => "FEDEXOVERSIZE",
                    self::AREA_LAST_ENUM_AHS_WEIGHT => "FEDEX-GROUND",
                    self::AREA_LAST_ENUM_WEIGHT_RANGE => "FEDEX-HD-NJ",
                    self::AREA_LAST_ENUM_AHS => "FEDEX-HD-NJ",
                    self::AREA_LAST_ENUM_NORMAL => "FEDEX-HOMEDELIVERY",
                    self::AREA_LAST_ENUM_UPS => "UPSGROUND",
                ]
            ]
        ];
    }

    /**
     * 获取code码
     *
     * @return mixed|string
     */
    public function getCode()
    {
        if (!empty($this->config[$this->areaFirstEnumKey][$this->areaNextEnumKey][$this->areaLastEnumKey])) {
            return $this->config[$this->areaFirstEnumKey][$this->areaNextEnumKey][$this->areaLastEnumKey];
        } else {
            return $this->getDefaultCode()[$this->areaFirstEnumKey][$this->areaNextEnumKey][$this->areaLastEnumKey];
        }
    }

}

/*
 * 调试参数对应结果
 *
$areaEnum = Code::AREA_ENUM_US_WEST;
$areaChildEnum = Code::AREA_NEXT_ENUM_NORMAL;

$storehouse = ["us_area" => $areaEnum, "name" => "1"];
$info = [
    "type" => 3,
    "weight" => null
];
$config = [
    $areaEnum => [$areaChildEnum => [
        "weight_range" => null,
        "ahs_weight" => null,
        "oversize" => null,
        "ups" => null,
        "ahs" => null
    ]]
];
*/

$storehouse = $info = $config = [];
//$config["US_EAST"]["normal"]["ups"] = "sadfsad";

/*
 * 通过获取多维数组每个节点的key来获取最终的code码
 * 参数没有给定code码的 从默认节点code码中获取 获取失败可抛出异常
 */
$code = Code::getInstance($storehouse, $info, $config)->setAreaLevelEnumKey()->getCode();
echo $code . PHP_EOL;
